#include "fig_level.h"
#include "fig_background.h"
#include "fig_background_enemy.h"
#include "fig_enemy_manager.h"
#include "fig_player_craft.h"
#include "fighter.h"
#include "fig_moving_particles.h"
#include "pvu_shadow.h"
#include "fig_pickup_manager.h"
#include "fig_sounds.h"
#include "fig_sfx_manager.h"
#include "fig_enemybullet_master.h"
#include "gen_game_state.h"
#include "fig_playerbullet_master.h"
#include "fig_sfx_manager.h"
#include "fig_award_tracker.h"
#include "fig_enemy_pathcraft.h"
#include "fig_bullet.h"
#include "fig_bonefile_cache.h"
#include "fig_enemy_formationcraft.h"
#include "fig_conversation.h"
#include "fig_trophie_notification.h"
#include "fig_constants.h"
#include "fig_ui_levelcomplete.h"
#include "fig_bonefile_cache.h"

#include "resman/resman.h"
#include "num/rand.h"
#include "input/joystick.h"
#include "script/scripthelper.h"
#include "gameflow/ui_popup.h"

#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging
#include <cassert>

#include <algorithm>


using namespace script;


const  float							FIGLevel::ENEDLESS_SPAWN_SMLL_MAX_DURATION = 2.0f;
const  float							FIGLevel::ENEDLESS_SPAWN_MINIBOSS_MAX_DURATION = 5.0f;
const  float							FIGLevel::ENEDLESS_SPAWN_BOSS_MAX_DURATION = 240.0f;

const  float							FIGLevel::ENEDLESS_SPAWN_SMALL_MIN_DURATION= 0.1f;
const  float							FIGLevel::ENEDLESS_SPAWN_MINIBOSS_MIN_DURATION = 0.5f;
const  float							FIGLevel::ENEDLESS_SPAWN_BOSS_MIN_DURATION = 60.0f;

const  float							FIGLevel::ENEDLESS_SPAWN_SMLL_ACCELERATE = 0.02f;
const  float							FIGLevel::ENEDLESS_SPAWN_MINIBOSS_ACCELERATE  = 0.01f;
const  float							FIGLevel::ENEDLESS_SPAWN_BOSS_ACCELERATE  = 30.0f;




FIGLevel::FIGLevel(
				   const std::string& Level_BG_Main_Name,
				   const std::string& Level_BG_Name,
				   const std::string& Level_Enemy_Name) :
						m_NextEnemyIndex(0),
						m_Duration(0.0f),
						m_pShadow(NULL),
						m_OffsetY(0),
						m_ConversationDelay(0),
						m_IsEndless(false),						
						m_Random_SpawnSmall_Counter(0),
						m_bIsFirstTimeLoading(false)
{
	Load(Level_BG_Main_Name,Level_BG_Name,Level_Enemy_Name);

	//m_pShadow = new PVUShadow();

	int WIDTH = 512;
	if((float)GetGraphics()->GetScreenWidth() > 512.0f)
		WIDTH = 1024;

	int HEIGHT = 512;
	if((float)GetGraphics()->GetScreenHeight() > 512.0f)
		HEIGHT = 1024;

	if(m_pShadow)
		m_pShadow->Init(WIDTH , HEIGHT, 32);


	m_Endless_SpawnSmall_Duration = m_Endless_SpawnSmall_Counter = ENEDLESS_SPAWN_SMLL_MAX_DURATION;
	m_Endless_SpawnMiniBoss_Duration = m_Endless_SpawnMiniBoss_Counter= ENEDLESS_SPAWN_MINIBOSS_MAX_DURATION;
	m_Endless_SpawnBoss_Duration = m_Endless_SpawnBoss_Counter = ENEDLESS_SPAWN_BOSS_MAX_DURATION;
	
	m_Random_SpawnSmall_Counter = 2.0f;

	

}

FIGLevel::EnemyInfo::EnemyInfo() : 
					TimeAfter(0),
					Duration(0),
					Count(0),
					DelaySpawn(0),
					SpawnPositionX(0),
					EnemyTypeEnumInt(FIGEnemyCraft::ENEMY_TYPES_NONE),
					NameCRC(0),
					SpawnTypeEnumInt(FIGPickup::PICKUP_TYPE_NONE),
					FlyingPathEnumInt(FIGFlyingPath::PATH_NONE),
					FormationEnumInt(FIGEnemyFormationCraft::FORMATION_NONE)
{
		
}

void	FIGLevel::Load(
						const std::string& Level_BG_Main_Name,
						const std::string& Level_BG_Name,
						const std::string& Level_Enemy_Name)
{
	
	Clear();
//#if defined(_PLATFORM_IOS) || defined (_PLATFORM_ANDROID)
	res::ResMan::Instance().FlushTexturesExceptUI();	
//#endif  

	
	if(!m_bIsFirstTimeLoading)
	{
		FIGBoneFileCache::Instance().ReadAndCacheFiles(NULL,NULL);
		m_bIsFirstTimeLoading = false;
	}
	
	
	LuaPlus::LuaState*	pScript = ScriptHelper::CreateLuaState();
	if (!ScriptHelper::DoFile(*pScript, Level_BG_Main_Name))
	{
		LuaPlus::LuaState::Destroy( pScript );
		//return;
	} 	
	
	else{
	// fix RAII bug
	{
		LuaPlus::LuaObject BgTable = pScript->GetGlobal("LevelInfo");
		for(int i =0; i <BgTable.GetTableCount(); i++)
		{
			LuaPlus::LuaObject Obj = BgTable.GetByIndex(i+1);

			std::string BackGroundName = ScriptHelper::GetTableString(Obj,"Name"); 
			math::Vec2 Pos = ScriptHelper::GetTableVec2(Obj,"Center");

			float Rotation = ScriptHelper::GetTableFloat(Obj,"Rotation");
			float Scale	   = ScriptHelper::GetTableFloat(Obj,"SizeScale",1.0f);
			int	  Layer = ScriptHelper::GetTableInt(Obj,"Layer",-1);

			float BackGroundSpeed = 0;
			float MoveScaleX = 0.0f;
			COLOR c = ColorfRGBA(1.0f,1.0f,1.0f,1.0f);

			if(!BackGroundName.empty())
			{
				FIGBackground* pBG = new FIGBackground( 
														BackGroundName , 
														Pos,
														BackGroundSpeed , 
														MoveScaleX,
														Rotation, 
														Scale,
														Layer,
														c
														);
				m_Backgrounds.push_back(pBG);
			}

		}
		
	}  
	LuaPlus::LuaState::Destroy( pScript );
	}
	//---------------------------------------------------
	
	pScript = ScriptHelper::CreateLuaState();
	if (!ScriptHelper::DoFile(*pScript, Level_BG_Name))
	{
		LuaPlus::LuaState::Destroy( pScript );
		//return;
	}else{ 

	 
	//-----------------------------------------------------
	// fix RAII bug
	{
		// Moving Backgrounds ( speed is differ according to Layer)
		LuaPlus::LuaObject  BgTable = pScript->GetGlobal("LevelInfo");
		for(int i =0; i <BgTable.GetTableCount(); i++)
		{
			LuaPlus::LuaObject Obj = BgTable.GetByIndex(i+1);

			std::string BackGroundName = ScriptHelper::GetTableString(Obj,"Name"); 
			math::Vec2 Pos = ScriptHelper::GetTableVec2(Obj,"Center");
            
			float TempScale =  FIGConstants::IPHONE4_HEIGHT /(float)GetGraphics()->GetScreenHeight();
			TempScale *= ( (float)GetGraphics()->GetScreenWidth() / FIGConstants::IPHONE4_WIDTH);
            Pos.y *= TempScale;
			
           	float Rotation = ScriptHelper::GetTableFloat(Obj,"Rotation");
			float Scale	   = ScriptHelper::GetTableFloat(Obj,"SizeScale",1.0f);
			int	  Layer = ScriptHelper::GetTableInt(Obj,"Layer",-1);
			std::string	  EnemyClassName = ScriptHelper::GetTableString(Obj,"EnemyClassName");

			float BackGroundSpeed = 0;
			float MoveScaleX = 0.0f;
			COLOR c;

			if(Layer == 3)
			{
				// fastest
			BackGroundSpeed = 0.05f;
			MoveScaleX = 1.0f * 0.5f;
			float v = 1.0f;
			c =	ColorfRGBA(v,v,v,1.0f);
			}
			if(Layer == 2)
			{
			BackGroundSpeed = 0.025f;
			MoveScaleX = 1.0f * 0.5f * 0.5f;
			float v = 0.65f;
			c =	ColorfRGBA(v,v,v,1.0f);
			}
			if(Layer == 1)
			{
			BackGroundSpeed = 0.0125f;
			MoveScaleX = 1.0f * 0.5f * 0.5f * 0.5f;
			float v = 1.0f;
			c =	ColorfRGBA(v,v,v,1.0f);
			}
			if(Layer == 0)
			{
				// slowest
			BackGroundSpeed = 0.0125f * 0.5f;;
			MoveScaleX = 1.0f * 0.5f * 0.5f * 0.5f;
			float v = 0.8f;
			c =	ColorfRGBA(v,v,v,1.0f);
			}
					
			if(!BackGroundName.empty())
			{
				if(FIGBackgroundEnemy::MapNameToType(BackGroundName) == FIGBackgroundEnemy::LAUNCHER_TYPE_UNKNOWN)
				{
					FIGBackground* pBG = new FIGBackground( 
															BackGroundName , 
															Pos,
															BackGroundSpeed , 
															MoveScaleX,
															Rotation, 
															Scale,
															Layer,
															c
															);
					m_Backgrounds.push_back(pBG);					
				}
				else
				{
					FIGBackgroundEnemy* pBG = new FIGBackgroundEnemy( 
															BackGroundName , 
															Pos,
															BackGroundSpeed , 
															MoveScaleX,
															Rotation, 
															Scale,
															Layer
															);
					m_Backgrounds.push_back(pBG);
					pBG->SetColor(0.8f,0.8f,0.8f,1.0f);
				}
			}

		}
	
	}  
	LuaPlus::LuaState::Destroy( pScript );
	}
	//---------------------------------------------------

	pScript = ScriptHelper::CreateLuaState();
	if (!ScriptHelper::DoFile(*pScript, Level_Enemy_Name))
	{
		LuaPlus::LuaState::Destroy( pScript );
		//return;
	}  else {
	
	// fix RAII bug
	{
		LuaPlus::LuaObject EnemyTable = pScript->GetGlobal("Enemies");
		if(!EnemyTable.IsTable()) 
		{}
		else
		{
			for(int i =0; i <EnemyTable.GetTableCount(); i++)
			{
				LuaPlus::LuaObject Obj = EnemyTable.GetByIndex(i+1);

				std::string ClassName = ScriptHelper::GetTableString(Obj,"ClassName");
				std::string Name = ScriptHelper::GetTableString(Obj,"Name");
				int TimeAfter = ScriptHelper::GetTableInt(Obj,"TimeAfter");
				int Duration = ScriptHelper::GetTableInt(Obj,"Duration");
				std::string Intro = ScriptHelper::GetTableString(Obj,"Intro");
				std::string Outtro = ScriptHelper::GetTableString(Obj,"OutTro");
				int Count = ScriptHelper::GetTableInt(Obj,"Count");
				float DelaySpawn = ScriptHelper::GetTableFloat(Obj,"DelaySpawn" , 0.3f);
				std::string Pickup = ScriptHelper::GetTableString(Obj,"Pickup");
				float SpawnPositionX = ScriptHelper::GetTableFloat(Obj,"SpawnPositionX", 0.5f); 
			
				FIGLevel::EnemyInfo *pInfo = new FIGLevel::EnemyInfo();
				
				pInfo->Name = Name;
				pInfo->TimeAfter = TimeAfter;
				pInfo->Duration = Duration;
				if(!Intro.empty())
				{
					pInfo->FlyingPathEnumInt = FIGFlyingPath::MapNameToType(Intro);
					if(pInfo->FlyingPathEnumInt == FIGFlyingPath::PATH_NONE )
						pInfo->FormationEnumInt = FIGEnemyFormationCraft::MapNameToType(Intro);
					else
						pInfo->FormationEnumInt = FIGEnemyFormationCraft::FORMATION_NONE;
				}
				
				if(!Name.empty())
					pInfo->NameCRC = num::CRC32::Instance().StrCRC(Name);
				else
					pInfo->NameCRC = 0;

				pInfo->Count = Count;
				if(DelaySpawn == 0)
					pInfo->DelaySpawn = 0.1f;
				else
					pInfo->DelaySpawn = DelaySpawn;

				pInfo->SpawnTypeEnumInt = FIGPickup::MapNameToType(Pickup);
				pInfo->SpawnPositionX = SpawnPositionX;			
				pInfo->EnemyTypeEnumInt = FIGEnemyCraft::MapNameToType(ClassName);
				m_EnemyInfos.push_back(pInfo);
				
				
			}
		}
	} 

	LuaPlus::LuaState::Destroy( pScript );
	}

	if(m_EnemyInfos.size() == 0)
		m_IsEndless = true;


	//------------------------
	/*
	// last one is boss .. just cache him for faster load
	int LastOne = (int)m_EnemyInfos.size();
	if(LastOne > 0)
	{
		EnemyInfo* pInfoBoss = m_EnemyInfos[LastOne - 1];
		FIGEnemyManager::Instance().Spawn(pInfoBoss);   
	}
	FIGEnemyManager::Instance().ForceKillAll();
	*/
	//--------------------
	
#ifdef _PLATFORM_ANDROID
	CacheDrawLevel();
#else
	FIGSFXManager::Instance().Cache();
#endif
	
	StartNewLevel();
	
	FIGConversation::Instance().StartConvoLevel(m_ConversationDelay);
	float Delay =	m_ConversationDelay;
	for(int i = (int)m_Backgrounds.size() - 1; i >= 0 ; i--)
	{
		FIGBackground* pTempBG = m_Backgrounds[i];
		pTempBG->MoveUpForSec(Delay);		
	}

	Fighter::Instance().ResetDebugValues(m_ConversationDelay);
	
}


void	FIGLevel::CacheDrawLevel()
{
	
    //return;

	ui::UISprite TempSprite;
	std::vector<std::string> SpriteFiles;

	bool	UseFilter = GetGraphics()->GetFilter2D();
	GetGraphics()->SetFilter2D(true);
	GetGraphics()->Start2D();
	GetGraphics()->Clear(0xFFFFFFFF);
	GetGraphics()->BeginScene();

	// ---------------- Cache From Files --------------------------
	//CacheDrawFile( "effects/sprites.lua");
	//CacheDrawFile( "ui_img/sprites_to_cache.lua");
	//CacheDrawFile( "img/sprites_to_cache.lua");
	//-------------------------------------------------------------

	FIGSFXManager::Instance().Cache();   

	//return;
	// OGL texture can't upload quckly enough 
	// we need to draw offscreen first to avoid rendering white textures

	
	//----------------- Cache Player -------------------------
	FIGPlayerCraft::Instance().CacheRender();

	//----------------- Cache Bullets -------------------------
	for(int i = 0; i < (int)FIGBullet::BULLET_TYPE_C; i++)
	{
		FIGBullet::BULLET_TYPES BLType = (FIGBullet::BULLET_TYPES)i;
		SpriteFiles.push_back(FIGBullet::GetSpriteNameByType(BLType) );
	}
	// ---------------- Cache BACKGROUND --------------------------	

	/*
	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{	
		FIGBackground* pBG = m_Backgrounds[i];
		if(pBG->IsHitAble())
		{
			FIGBackgroundEnemy* pObj = (FIGBackgroundEnemy*)pBG;
			std::string BoneFileName = pObj->GetBoneFileName();
			FIGBoneFileCache::BoneFileData* pBoneFileData = FIGBoneFileCache::Instance().GetBoneFileDataByFileName(BoneFileName);
			
			if(pBoneFileData)
			{
				for(int i = 0; i < (int) (pBoneFileData->m_BoneDatas.size()); i++)
				{
					FIGBoneFileCache::BoneData * pBoneData = pBoneFileData->m_BoneDatas[i];
					SpriteFiles.push_back(pBoneData->Name);
				}
			}
		}
		else
		{
			SpriteFiles.push_back(m_Backgrounds[i]->GetFile());       
		}
	}
	SpriteFiles.push_back("spot");
	*/

	//----------------- Cache Pickup -------------------------
	
	for(int i = 0; i < (int)m_EnemyInfos.size(); i++)
	{
		FIGPickup::PICKUP_TYPES PKType = (FIGPickup::PICKUP_TYPES) m_EnemyInfos[i]->SpawnTypeEnumInt;
		SpriteFiles.push_back( FIGPickup::GetSpriteFile1(PKType));		
		std::string Temp = FIGPickup::GetSpriteFile2(PKType);
		if(!Temp.empty())
		SpriteFiles.push_back(Temp);		
	}  	
	// force these ( they changed one to another )
	SpriteFiles.push_back( FIGPickup::GetSpriteFile1(FIGPickup::PICKUP_TYPE_WEAPON_BLUE));
	SpriteFiles.push_back( FIGPickup::GetSpriteFile1(FIGPickup::PICKUP_TYPE_WEAPON_RED));
	SpriteFiles.push_back( FIGPickup::GetSpriteFile1(FIGPickup::PICKUP_TYPE_WEAPON_GREEN));
	SpriteFiles.push_back( FIGPickup::GetSpriteFile1(FIGPickup::PICKUP_TYPE_1UP));

	//----------------- Cache Enemies -------------------------


	// Cache Small
	SpriteFiles.push_back("enemy_fly");
	SpriteFiles.push_back("enemy_kite");
	SpriteFiles.push_back("enemy_predator");
	SpriteFiles.push_back("enemy_sci_fi_fish");
	SpriteFiles.push_back("enemy_ufo");
	SpriteFiles.push_back("blue_spider");


	// From Level
	for(int i = 0; i < (int)m_EnemyInfos.size(); i++)
	{
		FIGLevel::EnemyInfo* pInfo = m_EnemyInfos[i];
		if(!pInfo->Name.empty())
		{
			SpriteFiles.push_back(pInfo->Name);
		}
		else
		{
			std::string BoneFile = FIGEnemyCraft::MapTypeToBoneFile((FIGEnemyCraft::ENEMY_TYPES) (pInfo->EnemyTypeEnumInt));
			FIGBoneFileCache::BoneFileData* pBoneFileData = FIGBoneFileCache::Instance().GetBoneFileDataByFileName(BoneFile);
			
			if(pBoneFileData)
			{
				for(int i = 0; i < (int)( pBoneFileData->m_BoneDatas.size()); i++)
				{
					FIGBoneFileCache::BoneData * pBoneData = pBoneFileData->m_BoneDatas[i];
					SpriteFiles.push_back(pBoneData->Name);
				}
			}

		}
	}


	//------------------UI--------------------------------
	//SpriteFiles.push_back("comic");

	//----------------- Rendering -------------------------
	// Render All Sprites to Cache
	std::sort( SpriteFiles.begin(), SpriteFiles.end() );       
	std::vector<std::string>::iterator new_end_pos;
    new_end_pos = std::unique( SpriteFiles.begin(), SpriteFiles.end() );
    SpriteFiles.erase( new_end_pos, SpriteFiles.end() );

   _LOG(MSG_COMMENT, "Cache Count  " << SpriteFiles.size());
	for(int i = 0; i < (int)SpriteFiles.size(); i++)
	{
		_LOG(MSG_COMMENT, SpriteFiles[i]);
		if(!SpriteFiles[i].empty())
		{
			TempSprite.Create(SpriteFiles[i]);
			TempSprite.m_Pos = math::Vec2(-1.0f,-1.0f);
			TempSprite.m_Size = math::Vec2(0.025f,0.25f);
			TempSprite.Render();
			
		}
	}

	//----------------- Cache UI -------------------------
	GetGraphics()->Clear(ColorfRGBA(0,0,0,1));
	//ui::UIManager::Instance().Render();
	GetGraphics()->EndScene();
	GetGraphics()->Present();
	GetGraphics()->SetFilter2D(UseFilter);

	//-------------------------------------------
	
	

}

void	FIGLevel::CacheDrawFile(const std::string& File)
{
	ui::UISprite TempSprite;

	LuaPlus::LuaState*	pScript = ScriptHelper::CreateLuaState();
	if (!ScriptHelper::DoFile(*pScript, File))
	{
		LuaPlus::LuaState::Destroy( pScript );
		return;
	} 	
	// fix RAII bug
	{
		LuaPlus::LuaObject BgTable = pScript->GetGlobal("Sprites");
		for(int i =0; i <BgTable.GetTableCount(); i++)
		{
			LuaPlus::LuaObject Obj = BgTable.GetByIndex(i+1);

			std::string Name = ScriptHelper::GetTableString(Obj,"Name"); 
			TempSprite.Create(Name);
			TempSprite.m_Pos = math::Vec2(-1.0f,-1.0f);
			TempSprite.RenderRotated();
			
		}
	}
    LuaPlus::LuaState::Destroy( pScript );
}


void	FIGLevel::StartNewLevel()
{
	m_NextEnemyIndex = 0;
	

	int ECount = 0;
	int SCount = 0;
	for(int i = 0; i < (int)m_EnemyInfos.size(); i++)
	{
		if( m_EnemyInfos[i]->EnemyTypeEnumInt == FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_DECAL)
			continue;
		if( m_EnemyInfos[i]->EnemyTypeEnumInt == FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_SLOW)
			continue;
		if( m_EnemyInfos[i]->EnemyTypeEnumInt == FIGEnemyCraft::ENEMY_TYPES_SPACEROCK_FAST)
			continue;

		ECount += m_EnemyInfos[i]->Count;
		
		//deprecated
		//if(m_EnemyInfos[i]->SpawnTypeEnumInt == ((int)(FIGPickup::PICKUP_TYPE_STAR)))
		//	SCount++;
	}

	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		if(pBG->IsHitAble())
			ECount++;
	}

	FIGAwardTracker::Instance().Start( ECount ,SCount);
	FIGTrophieNotification::Instance().ClearLastTrophieID();
	
	
}

FIGLevel::~FIGLevel()
{
	Clear();
	
	
}

void	FIGLevel::Clear()
{
   for(int i = 0; i < (int)m_EnemyInfos.size(); i++)
	{
		FIGLevel::EnemyInfo *pInfo = m_EnemyInfos[i];
		UTIL_SAFE_DELETE(pInfo);
	}
	m_EnemyInfos.resize(0);

	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBg = m_Backgrounds[i];
		UTIL_SAFE_DELETE(pBg);
	}
	m_Backgrounds.resize(0);

	FIGEnemyManager::Instance().Clear();

	FIGPickupManager::Instance().Clear();

	FIGEnemyBulletMaster::Instance().Clear();

	FIGPlayerBulletMaster::Instance().Clear();
	
	// call last ( bullet might ref sfx )
	FIGSFXManager::Instance().Clear();

}
	
void	FIGLevel::Render(const math::Vec2& Offset, float Scale)
{
	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		if(!pBG->IsForeGround())		
			pBG->Render(Offset,Scale);
	}

	FIGMovingParticles::Instance().Render(Offset,Scale);
	FIGEnemyManager::Instance().RenderDecal(Offset,Scale);

	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		if(pBG->IsForeGround())		
			pBG->Render(Offset,Scale);
	}


	
													    
	if(m_pShadow)
		m_pShadow->ShowCache();

	FIGPlayerBulletMaster::Instance().Render(Offset,Scale);

	FIGEnemyManager::Instance().Render(Offset,Scale);

	FIGPlayerCraft::Instance().Render(Offset,Scale);

	FIGEnemyBulletMaster::Instance().Render(Offset, Scale);
    
	FIGPickupManager::Instance().Render(Offset,Scale);
}

void	FIGLevel::RenderDebug(const math::Vec2& Offset, float Scale)
{
	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		pBG->RenderDebug(Offset,Scale);
	}

	FIGPlayerCraft::Instance().RenderDebug(Offset,Scale);

	FIGEnemyManager::Instance().RenderDebug(Offset,Scale);

	FIGPickupManager::Instance().RenderDebug(Offset,Scale);
}

void	FIGLevel::RenderShadow(const math::Vec2& Offset, float Scale)
{
	

	
}

void	FIGLevel::Tick(float dt)
{
	
	for(int i = (int)m_Backgrounds.size() - 1; i >= 0 ; i--)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		pBG->Tick(dt);
		
	}

	FIGMovingParticles::Instance().Tick(dt);

	FIGPlayerCraft::Instance().Tick(dt);

	FIGEnemyManager::Instance().Tick(dt);

	FIGEnemyBulletMaster::Instance().Tick(dt);

	FIGPickupManager::Instance().Tick(dt);


	if(m_IsEndless)
	{
		Tick_Endless(dt);
	}
	else
	{
        
		if(m_ConversationDelay > 0)
			m_ConversationDelay -= dt;
		else
		{
		

			if ( m_NextEnemyIndex < (int)m_EnemyInfos.size())
			{
				// Randomly Spawn Small Enemies
				if(m_Random_SpawnSmall_Counter > 0)
				{
					m_Random_SpawnSmall_Counter  -= dt;
					if(m_Random_SpawnSmall_Counter <= 0)
					{
						SpawnRandomSmall();
						return;
					}
				}

				m_Duration += dt;

				FIGLevel::EnemyInfo *pInfo = m_EnemyInfos[m_NextEnemyIndex];

				if( m_Duration > pInfo->TimeAfter)
				{
					m_NextEnemyIndex++;
					m_Duration = 0;
					FIGEnemyManager::Instance().Spawn(pInfo);
					
				}

			}
		}
	}
	
	if (m_pShadow)
	{
		math::Vec2 Offset = Fighter::Instance().GetOffset();
		float Scale = Fighter::Instance().GetScale();

		if (m_pShadow->StartCache())
		{
			FIGPlayerCraft::Instance().RenderShadow(Offset,Scale);
			FIGEnemyManager::Instance().RenderShadow(Offset,Scale);
			
			m_pShadow->EndCache();
		}
	}


	for(int i = (int)m_Backgrounds.size() - 1; i >= 0 ; i--)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		if(pBG->IsToDelete())
		{
			pBG->Clear();
			UTIL_SAFE_DELETE(pBG);
			m_Backgrounds.erase(m_Backgrounds.begin() + i);
		}
		
	}
	
}

void	FIGLevel::Tick_Endless(float dt)
{
	m_Endless_SpawnSmall_Counter -= dt; 
	if( m_Endless_SpawnSmall_Counter <= 0)
	{
		SpawnEndlessSmall();
	}

	m_Endless_SpawnMiniBoss_Counter -= dt; 
	if( m_Endless_SpawnMiniBoss_Counter <= 0)
	{
		SpawnEndlessMiniBoss();
	}

	m_Endless_SpawnBoss_Counter -= dt; 
	if( m_Endless_SpawnBoss_Counter <= 0)
	{
		SpawnEndlessBoss();
	}
}

void	FIGLevel::SpawnRandomSmall()
{
	FIGLevel::EnemyInfo pEnemyInfo;
	m_Random_SpawnSmall_Counter = 2.0f;
	

	pEnemyInfo.Count = 1;
	std::string ClassName = "";
	std::string Name = "";
	std::string Intro = "";
	

	ClassName = "normal";
	int RandVal = num::RAND32::Instance().RandInt(1,5);
	switch (RandVal)
	{
		case 1: Name = "enemy_fly"; break;
		case 2: Name = "enemy_kite"; break;		
		case 3: Name = "enemy_predator"; break;
		case 4: Name = "enemy_sci_fi_fish"; break;
		case 5: Name = "enemy_ufo"; break;						
		case 6: Name = "blue_spider";
				ClassName = "backattacker";break;
	}
	
	RandVal = num::RAND32::Instance().RandInt(1,7);
	switch (RandVal)
	{
		case 1: Intro = "Side_Rotate_Right"; break;
		case 2: Intro = "Left_Coner_To_Right_Coner1"; break;		
		case 3: Intro = "Right_Coner_To_Left_Coner1"; break;
		case 4: Intro = "ComeRight_Circle"; break;
		case 5: Intro = "ComeLeft_Circle"; break;
		case 6:	Intro = "Left_To_Right_Diagonal"; break;
		case 7: Intro = "Right_To_Left_Diagonal"; break;
	}
	

	float SpawnPositionX = 0.5f;

	pEnemyInfo.Name = Name;
	pEnemyInfo.DelaySpawn = 0.1f;
	pEnemyInfo.Duration = 0;
	pEnemyInfo.TimeAfter = 0;
	
	if(!Intro.empty())
	{
		pEnemyInfo.FlyingPathEnumInt = FIGFlyingPath::MapNameToType(Intro);
		if(pEnemyInfo.FlyingPathEnumInt == FIGFlyingPath::PATH_NONE )
			pEnemyInfo.FormationEnumInt = FIGEnemyFormationCraft::MapNameToType(Intro);
		else
			pEnemyInfo.FormationEnumInt = FIGEnemyFormationCraft::FORMATION_NONE;
	}
	
	if(!Name.empty())
		pEnemyInfo.NameCRC = num::CRC32::Instance().StrCRC(Name);
	else
		pEnemyInfo.NameCRC = 0;

	
	pEnemyInfo.SpawnTypeEnumInt = FIGPickup::PICKUP_TYPE_NONE;
	pEnemyInfo.SpawnPositionX = SpawnPositionX;			
	pEnemyInfo.EnemyTypeEnumInt = FIGEnemyCraft::MapNameToType(ClassName);    			

	
	FIGEnemyManager::Instance().Spawn(&pEnemyInfo);
	
}


void	FIGLevel::SpawnEndlessSmall()
{
	
	/*
	m_Endless_SpawnSmall_Counter = m_Endless_SpawnSmall_Duration;
	if(m_Endless_SpawnSmall_Duration > ENEDLESS_SPAWN_SMALL_MIN_DURATION )
		m_Endless_SpawnSmall_Duration -= ENEDLESS_SPAWN_SMLL_ACCELERATE;

	pEnemyInfo.Count = 1;
	std::string ClassName = "";
	std::string Name = "";
	std::string Intro = "";
	std::string Pickup = "";

	int RandVal = num::RAND32::Instance().RandInt(1,15);  
	if(RandVal == 15)
	{
		Pickup = "STAR";
		ClassName = "formation";

		RandVal = num::RAND32::Instance().RandInt(1,2);  
		if(RandVal == 1)
		{
			Intro = "Formation_Triangle";
			pEnemyInfo.Count = 7;

		}
		else
		{
			Intro = "Formation_Line";
			pEnemyInfo.Count = 5;
		}

		RandVal = num::RAND32::Instance().RandInt(1,4);  
		switch (RandVal)
		{
			case 1: Name = "enemy_fly"; break;
			case 2: Name = "enemy_kite"; break;		
			case 3: Name = "enemy_predator"; break;
			case 4: Name = "enemy_sci_fi_fish"; break;  				
		}
	}
	else
	{
		ClassName = "normal";
		RandVal = num::RAND32::Instance().RandInt(1,7);  
		switch (RandVal)
		{
			case 1: Name = "enemy_fly"; break;
			case 2: Name = "enemy_kite"; break;		
			case 3: Name = "enemy_predator"; break;
			case 4: Name = "enemy_sci_fi_fish"; break;
			case 5: Name = "enemy_ufo"; break;
			case 6: Name = "space_rock";
					ClassName = "space_rock_fast";
					Pickup = "STAR";
					break;				
			case 7: Name = "blue_spider"; 
					ClassName = "backattacker";break;
		}
		
		
		if(RandVal <= 5)
		{
			
			RandVal = num::RAND32::Instance().RandInt(1,7);
			switch (RandVal)
			{
				case 1: Intro = "Side_Rotate_Right"; break;
				case 2: Intro = "Left_Coner_To_Right_Coner1"; break;		
				case 3: Intro = "Right_Coner_To_Left_Coner1"; break;
				case 4: Intro = "ComeRight_Circle"; break;
				case 5: Intro = "ComeLeft_Circle"; break;
				case 6:	Intro = "Left_To_Right_Diagonal"; break;
				case 7: Intro = "Right_To_Left_Diagonal"; break;
			}
		}
	}

	
	
	float SpawnPositionX = 0.5f;

	pEnemyInfo.Name = Name;
	pEnemyInfo.TimeAfter = 0;
	pEnemyInfo.Duration = 0;
	
	if(!Intro.empty())
	{
		pEnemyInfo.FlyingPathEnumInt = FIGFlyingPath::MapNameToType(Intro);
		if(pEnemyInfo.FlyingPathEnumInt == FIGFlyingPath::PATH_NONE )
			pEnemyInfo.FormationEnumInt = FIGEnemyFormationCraft::MapNameToType(Intro);
		else
			pEnemyInfo.FormationEnumInt = FIGEnemyFormationCraft::FORMATION_NONE;
	}
	
	if(!Name.empty())
		pEnemyInfo.NameCRC = num::CRC32::Instance().StrCRC(Name);
	else
		pEnemyInfo.NameCRC = 0;

	
	pEnemyInfo.DelaySpawn = 0.1f;
	

	pEnemyInfo.SpawnTypeEnumInt = FIGPickup::MapNameToType(Pickup);
	pEnemyInfo.SpawnPositionX = SpawnPositionX;			
	pEnemyInfo.EnemyTypeEnumInt = FIGEnemyCraft::MapNameToType(ClassName);    			

	FIGEnemyManager::Instance().Spawn(pEnemyInfo);
	*/
}

void	FIGLevel::SpawnEndlessMiniBoss()
{
	/*
	m_Endless_SpawnMiniBoss_Counter = m_Endless_SpawnMiniBoss_Duration;
	if(m_Endless_SpawnMiniBoss_Duration > ENEDLESS_SPAWN_MINIBOSS_MIN_DURATION)
		m_Endless_SpawnMiniBoss_Duration -= ENEDLESS_SPAWN_MINIBOSS_ACCELERATE;

	pEnemyInfo.Count = 1;
	std::string ClassName = "";
	std::string Name = "";
	std::string Intro = "";
	std::string Pickup = "";

	int RandVal = num::RAND32::Instance().RandInt(1,9);  
	switch (RandVal)
	{
		case 1: ClassName = "miniboss_hulk"; break;
		case 2: ClassName = "miniboss_cobra"; break;		
		case 3: ClassName = "miniboss_meganito"; break;
		case 4: ClassName = "miniboss_fox"; break; 
		case 5: ClassName = "miniboss_pron"; break; 
		case 6: ClassName = "miniboss_shark"; break; 
		case 7: ClassName = "miniboss_plato"; break; 
		case 8: ClassName = "miniboss_wolf"; break; 
		case 9: ClassName  = "normal_triangle"; break;


	}

	Pickup = "STAR"; 	
	float SpawnPositionX = 0.5f;
	RandVal = num::RAND32::Instance().RandInt(1,3);  
	switch (RandVal)
	{
		case 1: SpawnPositionX = 0.3f; break;
		case 2: SpawnPositionX = 0.5f;   break;
		case 3: SpawnPositionX =  0.75f; break;
	}     

	pEnemyInfo.Name = Name;
	pEnemyInfo.TimeAfter = 0;
	pEnemyInfo.Duration = 0;
	
	if(!Name.empty())
		pEnemyInfo.NameCRC = num::CRC32::Instance().StrCRC(Name);
	else
		pEnemyInfo.NameCRC = 0;
     	
	pEnemyInfo.DelaySpawn = 0.1f; 	

	pEnemyInfo.SpawnTypeEnumInt = FIGPickup::MapNameToType(Pickup);
	pEnemyInfo.SpawnPositionX = SpawnPositionX;			
	pEnemyInfo.EnemyTypeEnumInt = FIGEnemyCraft::MapNameToType(ClassName);    			

	FIGEnemyManager::Instance().Spawn(pEnemyInfo);
	*/
}

void	FIGLevel::SpawnEndlessBoss()
{
	/*
	m_Endless_SpawnBoss_Counter = m_Endless_SpawnBoss_Duration;
	if(m_Endless_SpawnBoss_Duration > ENEDLESS_SPAWN_BOSS_MIN_DURATION)
		m_Endless_SpawnBoss_Duration -= ENEDLESS_SPAWN_BOSS_ACCELERATE;

	pEnemyInfo.Count = 1;
	std::string ClassName = "";
	std::string Name = "";
	std::string Intro = "";
	std::string Pickup = "";

	int RandVal = num::RAND32::Instance().RandInt(1,7);  
	switch (RandVal)
	{
		
		case 1: ClassName = "boss_hummer"; break;
		case 2: ClassName = "boss_boffer"; break;		
		case 3: ClassName = "boss_beast"; break;
		case 4: ClassName = "boss_destoryer"; break; 
		case 5: ClassName = "boss_gyver"; break; 
		case 6: ClassName = "boss_eagle"; break; 
		case 7: ClassName = "boss_u14"; break;

	}

	Pickup = "STAR"; 	
	float SpawnPositionX = 0.5f;
	 

	pEnemyInfo.Name = Name;
	pEnemyInfo.TimeAfter = 0;
	pEnemyInfo.Duration = 0;
	
	if(!Name.empty())
		pEnemyInfo.NameCRC = num::CRC32::Instance().StrCRC(Name);
	else
		pEnemyInfo.NameCRC = 0;
     	
	pEnemyInfo.DelaySpawn = 0.1f; 	

	pEnemyInfo.SpawnTypeEnumInt = FIGPickup::MapNameToType(Pickup);
	pEnemyInfo.SpawnPositionX = SpawnPositionX;			
	pEnemyInfo.EnemyTypeEnumInt = FIGEnemyCraft::MapNameToType(ClassName);    			

	FIGEnemyManager::Instance().Spawn(pEnemyInfo); 
	*/
}




bool	FIGLevel::HitTest(FIGBullet* pBullet)
{
	if(pBullet->GetPos().y < 0)
		return false;
	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		if(pBG->IsHitAble())
		{
			FIGBackgroundEnemy* pObj = (FIGBackgroundEnemy*)pBG;
			if(!pObj->IsInSideScreen())
				continue;
			if(pObj->HitTest(pBullet))
				return true;
		}
	}
	return false;
}

void	FIGLevel::DoDamangeToAll(float DamageAmount)
{
	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		if(pBG->IsHitAble())
		{
			FIGBackgroundEnemy* pObj = (FIGBackgroundEnemy*)pBG;
			if(!pObj->IsInSideScreen())
				continue;
			pObj->GotDamage(DamageAmount,NULL,true);
		}
	}
}

FIGLifeObj*		FIGLevel::GetTopidoTarget(FIGBullet* pBullet)
{
	std::vector<FIGLifeObj*> pObjs;
	FIGLifeObj* pReturnObj = NULL;

	for(int i = 0; i < (int)m_Backgrounds.size(); i++)
	{
		FIGBackground* pBG = m_Backgrounds[i];
		if(pBG->IsHitAble())
		{
			FIGBackgroundEnemy* pObj = (FIGBackgroundEnemy*)pBG;
			if( pObj->IsAlive() && 
				pObj->IsInSideScreen() && 
				pObj->IsHitAble()
				)
			{
				pObjs.push_back(pObj);
			}
		}
	}
	
	if(pObjs.size() > 0)
	{
		int Index = num::RAND32::Instance().RandInt(0,pObjs.size()-1);
		pReturnObj = pObjs[Index];		
	}

	pObjs.resize(0);
	return pReturnObj;

	
}

FIGLifeObj*	FIGLevel::HitTest_Laser(const math::Vec2& StartPos, 
								float Width,
								math::Vec2& HitPos
								)
{
	math::Vec2 HitTestPos = StartPos;

	while(HitTestPos.y > 0)
	{
		for(int i = 0; i < (int)m_Backgrounds.size(); i++)
		{
			FIGBackground* pBG = m_Backgrounds[i];
			if(pBG->IsHitAble())
			{
				FIGBackgroundEnemy* pObj = (FIGBackgroundEnemy*)pBG;
				if(!pObj->IsInSideScreen())
					continue;
				if(!pObj->IsHitAble())
					continue;
				if(!pObj->IsAlive())
					continue;

				HitPos = HitTestPos;
				if(pObj->HitTest(HitTestPos))
				{
					return pObj;
				}
			}
		}
	
		HitTestPos.y -= Width;
	}

	return NULL;
}

